package ru.spb.osll.myfit.server.execute;

import java.io.File;
import java.io.OutputStream;
import java.io.IOException;
import java.io.FileNotFoundException;
import java.io.OutputStreamWriter;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.MalformedURLException;
import java.util.LinkedList;
import java.util.List;
import java.util.Date;
import org.apache.log4j.Logger;

import ru.spb.osll.myfit.server.Configurator;
import ru.spb.osll.myfit.server.MyFitClassLoaderFactory;
import ru.spb.osll.myfit.server.fixtureiterator.FileFactory;
import ru.spb.osll.myfit.server.parser.TableParser;
import ru.spb.osll.myfit.util.FileHelper;

public class PageExecutorFactory {
  private Logger LOG = Logger.getLogger(PageExecutorFactory.class);
  private FileHelper m_helper;
  private final TableParser m_tableParser;
  private final String m_root;
  private final String m_fixtures;
  private final String m_jars;
  private final String m_execResults;
  private final String m_files;

  public PageExecutorFactory(Configurator configurator, FileHelper helper) {
    m_tableParser = new TableParser();
    m_root = configurator.getRoot();
    m_fixtures = configurator.getFixtures();
    m_jars = configurator.getJars();
    m_execResults = configurator.getTestResultsDirectory();
    m_files = configurator.getResources() + File.separator + "files";
    m_helper = helper;
  }

  public PageExecutor createPageExecutor(String pagePath) throws Exception {
    String base = m_helper.createUDir(m_execResults, pagePath);
    String uname = (new File(base)).getName();
    Date startTime = m_helper.parseUNameGetTime(uname);
    
    
    String root = base + File.separator + (new File(m_root)).getName();
    m_helper.copyDir(m_root, root);
    String fileName = base + File.separator + pagePath + ".html";

    URLClassLoader classLoader = getClassLoader(base, pagePath);

    File fitNesseRoot = new File(root).getAbsoluteFile();
    FixtureListenerImpl fixtureListener = new FixtureListenerImpl(m_tableParser);
    
    FitNesseTestRunner runner = new FitNesseTestRunner(fitNesseRoot.getParent(), fitNesseRoot.getName(),
        new MyFitFixtureLoader(classLoader), fixtureListener);
    
    PageWriter pageWriter = new PageWriter(fileName, m_files);

    PageExecutor executor = new PageExecutor(runner, pagePath, fixtureListener, pageWriter, startTime, uname);

    return executor;
  }

  private URLClassLoader getClassLoader(String base, String pagePath)
	throws MalformedURLException, FileNotFoundException, IOException {
    String fixtures = base + File.separator + "fixtures";
    String jars = base + File.separator + "jars";
    String dirName = (new File(base)).getName();
    
    m_helper.copyDir(m_fixtures, fixtures);
    m_helper.copyDir(m_jars, jars);
    
    String logDir = null;

    try {
      logDir = createLogConfigFile(base, dirName, pagePath);
    } catch (IOException e) {
      LOG.warn("Logfile for " + dirName + " have not been created", e);
    }

    URLClassLoader classLoader;
   
     if(logDir == null){
      classLoader = new MyFitClassLoaderFactory(new FileFactory()).createClassLoader(jars, fixtures);
    }else{
      List<URL> urls = new LinkedList<URL>();
      urls.add(new URL("file", "localhost", logDir + "/"));
      classLoader = new MyFitClassLoaderFactory(new FileFactory()).createClassLoader(urls, jars, fixtures);  
    }

    return classLoader;
  }
  
  /**
   * 
   * @param destDir - directory testExecutionResult/PageName
   * @param pageDir - name of directory for current executed page
   * @param pagePath
   * @return name of directory for log configuration file 
   * @throws IOException - creating log configuration file failed 
   */
  private String createLogConfigFile(String destDir, String pageDir, String pagePath) throws IOException{
    String loggerConfigDir = destDir + File.separator +"loggerconfig";
    String loggerConfigFile = loggerConfigDir + File.separator + "logconfig.properties";    
    
    m_helper.createDir(loggerConfigDir);
    
    OutputStream out = m_helper.openFile(loggerConfigFile);
    OutputStreamWriter writer = new OutputStreamWriter(out);
    
    String lineSeparator = System.getProperty("line.separator");
    
    //Never change symbol "/" to File.separator. Resource bundle will use this line.
    String loggerFile = m_execResults + "/" + pageDir+ "/" + pagePath + ".log";
    writer.write(String.format("logFile=%s", loggerFile));
    
    writer.write(lineSeparator);
    writer.write(String.format("loggerName=%s", pageDir));
    writer.write(lineSeparator);
    writer.close();
    out.close();
    return loggerConfigDir;
  }
  
}
